package net.randomice.emf.observables.runtime;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.databinding.observable.map.ComputedObservableMap;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.set.MappedSet;
import org.eclipse.emf.ecore.EObject;

@SuppressWarnings("deprecation")
public final class ObservableSetRootObjects<I extends EObject, R extends IObservableObject<I>>
		extends MappedSet {
	private final IObservableMap map;

	public ObservableSetRootObjects(IObservableSet input,
			Class<? extends R> rClass,
			final IObservableObject.AbstractCreator<I, R> rCreator) {
		this(input, new ComputedObservableMap(input, rClass) {
			Map<I, R> wrappedMap = new HashMap<I, R>();

			protected void unhookListener(Object key) {
				wrappedMap.remove(key);
			}

			protected void hookListener(Object key) {
			}

			protected Object doPut(Object key, Object value) {
				throw new UnsupportedOperationException();
			}

			@SuppressWarnings("unchecked")
			protected R doGet(Object key) {
				if (!wrappedMap.containsKey(key)) {
					I iKey = (I) key;
					R value = rCreator.createRoot(iKey);
					wrappedMap.put(iKey, value);
					return value;
				} else {
					return wrappedMap.get(key);
				}
			}
		});
	}

	public ObservableSetRootObjects(IObservableSet input, IObservableMap map) {
		super(input, map);
		this.map = map;
	}

	@SuppressWarnings("unchecked")
	public R get(I key) {
		return (R) map.get(key);
	}
}